package main

import (
	"archive/tar"
	"io"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"
	"sync"
)

// 定义变量只会赋值一次
var once sync.Once
var pathDelimiter string

// Exists 判断所给路径文件/文件夹是否存在
func Exists(path string) bool {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}

// IsDir 判断所给路径是否为文件夹
func IsDir(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return false
	}
	return s.IsDir()
}

// IsFile 判断所给路径是否为文件
func IsFile(path string) bool {
	return !IsDir(path)
}

// getFiles 获取所有文件
func getFiles(folder string, fileList *[]string) {
	pathDelimiter := getPathDelimiter()
	files, _ := ioutil.ReadDir(folder)
	for _, file := range files {
		if file.IsDir() {
			getFiles(folder+pathDelimiter+file.Name(), fileList)
		} else {
			fileTmp := folder + pathDelimiter + file.Name()
			*fileList = append(*fileList, fileTmp)
		}
	}
}

// getPathDelimiter 获取当前的路径分割符号，使用单例只获取一次即可
func getPathDelimiter() string {
	once.Do(func() {
		// 判断当前执行环境是Win或者Linux处理路径
		ostype := runtime.GOOS
		if ostype == "windows" {
			pathDelimiter = "\\"
		} else if ostype == "linux" {
			pathDelimiter = "/"
		}
		log.Printf("当前工作环境：%s ; 目录分割符：%s", ostype, pathDelimiter)
	})
	return pathDelimiter
}

// 获取当前工作路径
func getCurrentPath() string {
	currentPath, _ := os.Getwd()
	//log.Printf("当前工作目录: %s", currentPath)
	return currentPath
}

// tar 将切片中路径文件打包
func tarFilesFromArray(srcFiles []string, tarName string, tarCheckDirPath string) (string, error) {
	// 创建tar文件
	tarPathName := getCurrentPath() + getPathDelimiter() + tarName
	fw, err := os.Create(tarPathName)
	if err != nil {
		return tarPathName, err
	}
	defer fw.Close()

	// 通过 fw 创建一个 tar.Writer
	tw := tar.NewWriter(fw)
	// 如果关闭失败会造成tar包不完整
	defer func() {
		if err := tw.Close(); err != nil {
			log.Printf("关闭保存tar文件失败，报错信息:%#v ", err)
		}
	}()

	for _, fileName := range srcFiles {
		// 获取要打包的文件或目录的所在位置和名称
		//srcBase := filepath.Dir(filepath.Clean(fileName))
		//srcRelative := filepath.Base(filepath.Clean(fileName))
		//srcFullName := srcBase + srcRelative

		// 判断文件是否存在
		if !Exists(fileName) {
			log.Printf("文件不存在，名称为:%s", fileName)
			continue
		}
		// 获取文件信息
		fileInfo, _ := os.Stat(fileName)
		hdr, err := tar.FileInfoHeader(fileInfo, "")

		// 获取文件与我们要打包目录的相对路径作为包中的文件名 将 Win 分隔符换成 Linux 为了最终上传 Linux 服务器,删除开头的分隔符	
		hdr.Name = strings.Replace(strings.Replace(strings.TrimPrefix(fileName, tarCheckDirPath), "\\", "", 1),"\\","/",-1)
        //log.Printf("正在打包文件名-------->%s",hdr.Name)
		// tar包的默认格式，不支持中文路径，手动改成使用GNU格式
		hdr.Format = tar.FormatGNU
		// 将 tar 的文件信息 hdr 写入到 tw
		err = tw.WriteHeader(hdr)
		if err != nil {
			return tarPathName, err
		}

		// 将文件数据写入
		f, err := os.Open(fileName)
		defer f.Close()
		if err != nil {
			return tarPathName, err
		}
		if _, err = io.Copy(tw, f); err != nil {
			return tarPathName, err
		}
	}
	log.Printf("打包成功，包位置: %s", tarPathName)
	return tarPathName, nil
}
